package com.growthsee.rider.utils.SM;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.growthsee.rider.domain.RiderCarsInfo;
import com.growthsee.rider.domain.RiderPackage;
import com.growthsee.rider.domain.dto.RiderLoanInfoDto;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class SM2Utils {
    static ObjectMapper objectMapper;
    //生成随机秘钥对
    public static Map<String , String > generateKeyPair(){
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();

        String pubkey = Util.byteToHex(publicKey.getEncoded());
        String priKey = Util.byteToHex(privateKey.toByteArray());

        System.out.println("公钥: " + pubkey);
        System.out.println("私钥: " + priKey);

        Map map = new HashMap<String , String >();
        map.put("privateKey", priKey);
        map.put("publicKey", pubkey);
        return map;
    }

    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException
    {
        if (publicKey == null || publicKey.length == 0)
        {
            return null;
        }

        if (data == null || data.length == 0)
        {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
//      System.out.println("C2 " + Util.byteToHex(source));
//      System.out.println("C3 " + Util.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

    }

    //数据加密
    public static String encrypt(String publicKey, String data) throws IOException
    {
        return encrypt(Util.hexToByte(publicKey), data.getBytes());
    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
    {
        if (privateKey == null || privateKey.length == 0)
        {
            return null;
        }

        if (encryptedData == null || encryptedData.length == 0)
        {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = Util.byteToHex(encryptedData);
        /***分解加密字串
         * （C1 = C1标志位2位 + C1实体部分128位 = 130）
         * （C3 = C3实体部分64位  = 64）
         * （C2 = encryptedData.length * 2 - C1长度  - C2长度）
         */
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);

        //返回解密结果
        return c2;
    }

    //数据解密
    public static String decrypt(String privateKey, String encryptedData) throws IOException
    {
        return new String(decrypt(Util.hexToByte(privateKey), Util.hexToByte(encryptedData)));
    }



    public static void main(String[] args) throws Exception {

        RiderLoanInfoDto riderLoanInfoDto = new RiderLoanInfoDto();
        riderLoanInfoDto.setIdCardNo("510524199310084021");
        riderLoanInfoDto.setUserName("张三");
        riderLoanInfoDto.setAcctCard("6210986500003355669");
        riderLoanInfoDto.setBuyTime(new Date());
        riderLoanInfoDto.setStat(1);
        riderLoanInfoDto.setCreditStat(0);
        riderLoanInfoDto.setLoanStat(1);
        riderLoanInfoDto.setLoanDate("1231");
        riderLoanInfoDto.setTotalAmt(new BigDecimal(1231));
        riderLoanInfoDto.setLoanPeriods("12");
        riderLoanInfoDto.setNoClearPeriods("10");
        riderLoanInfoDto.setChannelMerName("渠道商");
        riderLoanInfoDto.setLoanNos("1111");
        List<RiderPackage> riderPackages = new ArrayList<>();
        RiderPackage riderPackage1 = new RiderPackage();
        riderPackage1.setLoanId(riderLoanInfoDto.getId());
        riderPackage1.setPackageName("heheh");
        riderPackage1.setStoreName("heheh");
        riderPackages.add(riderPackage1);
        riderLoanInfoDto.setRiderPackages(riderPackages);
        RiderCarsInfo carsInfo1 = new RiderCarsInfo();
        carsInfo1.setChangsh("厂商1");
        carsInfo1.setMendian("门店1");
        carsInfo1.setPingpmc("品牌1");
        carsInfo1.setXingh("类型1");
        RiderCarsInfo carsInfo2 = new RiderCarsInfo();
        carsInfo2.setChangsh("厂商2");
        carsInfo2.setMendian("门店2");
        carsInfo2.setPingpmc("品牌2");
        carsInfo2.setXingh("类型2");
        riderLoanInfoDto.setBuyCarsInfo(Arrays.asList(carsInfo1,carsInfo2));

        String plainText = toJSon(riderLoanInfoDto);
        byte[] sourceData = plainText.getBytes();
        String prik = "662A78472E55199A41CC893F02A87F4A8C735A5E8E55A52C062AE77C0553E207";
        String pubk = "0449030FB8D392D2425799101A06E4EC812F4C265939FF94E6E1408F4ECD34C455F6456BFB94E601B590FEFC0312EFE3F09BCEE3623E9F2076A0C4B3C52CB8928F";
        String cipherText = SM2Utils.encrypt(Util.hexToByte(pubk), sourceData);
        System.out.println("加密:"+cipherText);
        System.out.println("解密："+SM2Utils.decrypt(prik, "046223B79BB35ABDC188D35051620488EA4E6FD1A32E918B8681B92344588A7BA2203EA030B31B86391AD94BC4429207BDB97039C0E7AD924C7883A0FD3C7734C6C50BFB10CEA15C714C7C529C0672E685BAB0254CCCFC3E07EB703DFDCF28AB9A122C15733C6A74B6D84846FAF9F9E8DFD0CECFF918FB65B033EE7A95AEA9492E4CAAD489242C8A0FED8D0C112376A348B27149AB682430277466412E06D64D328570D32DDE162FABEB14CDC2AE4FBA0FFA2E58439916BFC85EB09A065A52D1D439D987B8D6999129D4F6393FD5AEA0221BB54534F33069143DD90A8DCAF4CD189C86F19C95D87CEE616EAF14D17CFAC30122EB9CDAF1F3385E121A3483BDCBDFC45149ADA7CB30A5C7BDA7CC062945C526C2CEF1302839063C87ED67FE155F0A6EF4E742A40605AF4D02DC7B574FA2F26FC3ED3A8BB4C6173F9F24102F3E4753C2B5DBB4681D2DB151FEFDBE"));

    }

    public static String toJSon(Object object) {
        if (objectMapper == null) {
            objectMapper = new ObjectMapper();
        }
        try {
            return objectMapper.writeValueAsString(object);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}
